package com.franklin.ideaplugin.easytesting.core.invoke;

import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import com.franklin.ideaplugin.easytesting.common.entity.MethodInvokeData;
import com.franklin.ideaplugin.easytesting.common.log.ILogger;
import com.franklin.ideaplugin.easytesting.common.log.LoggerFactory;
import com.franklin.ideaplugin.easytesting.core.rpc.NettyServer;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author Ye Junhui
 * @since 2023/5/21
 */
public class InstanceMethodInvoker implements IMethodInvoker {

    private static final ILogger log = LoggerFactory.getLogger(InstanceMethodInvoker.class);

    @Override
    public Object invoke(MethodInvokeData methodInvokeData, Class<?> targetClass, Method targetMethod, Class<?>[] paramTypes, Object[] params) throws Exception {
        try {
            if (targetClass.isEnum()){
                return invokeEnumMethod(methodInvokeData,targetClass, targetMethod, params);
            }
            Constructor<?> declaredConstructor = targetClass.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            Object instance = declaredConstructor.newInstance();
            return targetMethod.invoke(instance,params);
        } catch (Exception e) {
            log.error("Easy-Testing -> No Args Constructor not found",e);
            return null;
        }
    }

    /**
     * 执行枚举的实例方法
     *
     * @param methodInvokeData
     * @param targetClass
     * @param targetMethod
     * @param params
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private Object invokeEnumMethod(MethodInvokeData methodInvokeData, Class<?> targetClass, Method targetMethod, Object[] params) throws InvocationTargetException, IllegalAccessException {
        if (!targetClass.isEnum()){
            return null;
        }
        Class<? extends Enum> enumClazz = (Class<? extends Enum>) targetClass;
        Enum object = null;
        if (methodInvokeData.isEnumInstanceMethod() && StrUtil.isNotBlank(methodInvokeData.getEnumTarget())) {
            object = EnumUtil.fromString(enumClazz, methodInvokeData.getEnumTarget());
        }else {
            object = EnumUtil.getEnumAt(enumClazz, 0);
        }
        if (Objects.isNull(object)){
            return null;
        }
        return targetMethod.invoke(object,params);
    }
}
